<?php
/**
 * 解析函数
 */
class InspectFunc
{
    private $blocks = array();
    
    /**
     * 解析文档注视块并返回解析结果对象
     * 
     * @param  string $doc
     * @return InspectFunc
     */
    static function parse($doc)
    {
        return new self($doc);
    }

    private function __construct($block){
        $block = explode(PHP_EOL,$block);
        foreach($block as $bk=>$bv){
            $bv = preg_replace("/\s*\*\s*/",'',$bv);
            if($bv=='/' || empty($bv) || $bv==' '){
                unset($block[$bk]);
            }else{
                $block[$bk] = $bv;
            }
        }
        $this->blocks = array_values($block);
    }
    
    function getDescr(){
        $params = array();
        foreach($this->blocks as $bk=>$bv){
            if(substr($bv, 0, 1 ) != '@'){
                $params[] = $bv;
                unset($this->blocks[$bk]);
            }
        }
        return $params;
    }

    function getParams(){
        $params = array();
        foreach($this->blocks as $bk=>$bv){
            $row = explode(' ',$bv);
            if($row[0]=='@param'){
                $params[] = array(
                    'name'=>$row[1],
                    'type'=>$row[2],
                    'is_required'=>$row[3],
                    'descr'=>$row[4]
                );
                unset($this->blocks[$bk]);
            }
        }
        return $params;
    }
    
    function getExample(){
        $params = array();
        foreach($this->blocks as $bk=>$bv){
            $row = explode(' ',$bv);
            if($row[0]=='@uri'){
                $params['uri'] = $row[1];
                unset($this->blocks[$bk]);
            }elseif($row[0]=='@request'){
                $params['request'] = array('type'=>$row[1],'param'=>$row[2]);
                unset($this->blocks[$bk]);
            }elseif($row[0]=='@success'){
                $params['success'] = array('type'=>$row[1],'param'=>$row[2]);
                unset($this->blocks[$bk]);
            }elseif($row[0]=='@error'){
                $params['error'][] = array('type'=>$row[1],'param'=>$row[2]);
                unset($this->blocks[$bk]);
            }
        }
        return $params;
    }
    
    function getData(){
        $params = array();
        foreach($this->blocks as $bk=>$bv){
            $row = explode(' ',$bv);
            if($row[0]=='@data'){
                $params[] = array(
                    'name'=>$row[1],
                    'descr'=>$row[2],
                );
                unset($this->blocks[$bk]);
            }
        }
        return $params;
    }

    function getTag($tag){
        $params = '';
        foreach($this->blocks as $bk=>$bv){
            $row = explode(' ',$bv);
            if($row[0]==$tag){
                unset($row[0]);
                //$row = implode(' ',$row);
                $params = array_values($row);
                unset($this->blocks[$bk]);
            }
        }
        return $params;
    }

}

/**
 * 解析对象属性
 */
class InspectObj
{
    /**
     * 分析 DocComment，返回分析结果
     *
     * @param string $doc
     *
     * @return array
     */
    static function parse($doc)
    {
        $doc = trim(trim($doc), '/');
        $doc = trim(preg_replace('/^\s*\**( |\t)?/m', '', $doc));
        $matches = null;
        if(preg_match('/^\s*@\w+/m', $doc, $matches, PREG_OFFSET_CAPTURE))
        {
            $items = substr($doc, $matches[0][1]);
            $text  = trim(substr($doc, 0, $matches[0][1]));
        }
        else
        {
            $items = '';
            $text  = $doc;
        }

        return self::_format_items($items);
    }

    private static function _format_items($items)
    {
        $items = preg_split('/^\s*(@|#)/m', $items, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
        $arr = array();
        for ($offset = 0; $offset < count($items); $offset++)
        {
            $item = $items[$offset];
            if ($item == '@') continue;
            if ($item == '#')
            {
                $offset++;
                continue;
            }
            $arr[] = self::_format_item($item);
        }
        $ref_counts = array();
        $items = array();
        foreach ($arr as $item)
        {
            foreach ($item as $name => $value)
            {
                if (isset($items[$name]))
                {
                    if (!isset($ref_counts[$name]))
                    {
                        $ref_counts[$name] = true;
                        $items[$name] = array($items[$name], $value);
                    }
                    else
                    {
                        $items[$name][] = $value;
                    }
                }
                else
                {
                    $items[$name] = $value;
                }
            }
        }
        return $items;
    }

    private static function _format_item($item)
    {
        $segs = preg_split('/\s+/', trim($item), 2);
        $name = $segs[0];
        $params = isset($segs[1]) ? trim($segs[1]) : '';
        return array($name => self::_format_params($params));
    }

    private static function _format_params($params)
    {
        $params = self::arr($params, "\n");
        $return = array();
        $useKey = false;
        foreach ($params as $offset => $param)
        {
            $param = self::_format_param($param);
            if (is_array($param))
            {
                $useKey = true;
                $return[$param[0]] = $param[1];
            }
            else
            {
                $return[] = $param;
            }
        }
        if (!$useKey && count($return) == 1) $return = reset($return);
        if (empty($return)) return '';
        return $return;
    }

    private static function _format_param($param)
    {
        $pair = self::arr($param, ':');
        if (isset($pair[1]))
        {
            return $pair;
        }
        else
        {
            return $pair[0];
        }
    }

    static function arr($input, $delimiter = ',')
    {
        if (!is_array($input))
        {
            $input = explode($delimiter, $input);
        }
        $input = array_map('trim', $input);
        return array_filter($input, 'strlen');
    }

}
